// StpLibrary - by Steve T. Pham
// http://www.geocities.com/stevetpham

using System;
using System.Collections.Generic;
using System.Text;

namespace SteveTPham.QueryAnything.DataAccess
{
	/// <summary>
	/// ConnectionStringManager parses a ConnectionString into individual elements: Servicename,
	/// Databasename, UserID, Password, IntegratedSecurity.  Manager also merges elements into 
	/// fully-qualified ConnectionString.
	/// </summary>
	public class ConnectionStringManager
	{
		#region Enumerators
		#endregion

		#region Fields
		private string service;
		private string database;
		private string userid;
		private string password;
		private bool isIntegratedSecurity;

		private Dictionary<string, string> otherPairs = null;
		#endregion

		#region Constructors
		/// <summary>
		/// create an empty manager.  The caller is responsible for specifying the 
		/// </summary>
		public ConnectionStringManager()
		{
			Reset();
		}

		/// <summary>
		/// create a manager with a ConnectionString value.
		/// </summary>
		/// <param name="connectionString"></param>
		public ConnectionStringManager(string connectionString)
		{
			ConnectionString = connectionString;
		}

		/// <summary>
		/// create a manager with the individual elements.
		/// </summary>
		/// <param name="service"></param>
		/// <param name="database"></param>
		/// <param name="userid"></param>
		/// <param name="password"></param>
		/// <param name="integratedSecurity"></param>
		public ConnectionStringManager(string service, string database, string userid, string password, bool integratedSecurity)
		{
			this.service = service;
			this.database = database;
			this.userid = userid;
			this.password = password;
			this.isIntegratedSecurity = integratedSecurity;
		}
		#endregion

		#region Event Methods

		#region System Event Methods
		#endregion

		#region Application Event Methods
		#endregion

		#region Custom Event Methods
		#endregion

		#endregion

		#region Public Methods
		/// <summary>
		/// Reset all elements.
		/// </summary>
		public void Reset()
		{
			service = string.Empty;
			database = string.Empty;
			userid = string.Empty;
			password = string.Empty;
			isIntegratedSecurity = false;

			otherPairs = new Dictionary<string, string>();
		}

		/// <summary>
		/// Return a full ConnectionString.
		/// </summary>
		/// <returns></returns>
		[Obsolete("Consider using ConnectionString property", false)]
		public string MakeConnectionString()
		{
			if (IsInitialized)
				return string.Empty;

			StringBuilder s = new StringBuilder();

			s.AppendFormat("data source={0}", Service);

			if (IsIntegratedSecurity)
			{
				s.Append("; integrated security=true");
			}
			else
			{
				s.AppendFormat("; user id={0}; password={1}", Userid, Password);
			}

			if (!String.IsNullOrEmpty(database))
				s.AppendFormat("; initial catalog={0}", Database);

			if (otherPairs != null)
			{
				foreach (KeyValuePair<string, string> kv in otherPairs)
				{
					s.AppendFormat("; {0}={1}", kv.Key, kv.Value);
				}
			}

			return s.ToString();
		}

		/// <summary>
		/// Parse the ConnectionString and save the individual elements
		/// </summary>
		/// <param name="connectionString"></param>
		[Obsolete("Consider using ConnectionString property", false)]
		public void Parse(string connectionString)
		{
			Reset();

			if (String.IsNullOrEmpty(connectionString))
				return;

			string[] pairs = connectionString.Split(';');

			for (int i = 0; i < pairs.Length; i++)
			{
				if (string.IsNullOrEmpty(pairs[i]))
					continue;
				string[] tokens = pairs[i].Split('=');

				if (tokens.Length != 2)
					throw new ArgumentException("invalid pair: " + pairs[i]);

				string var = tokens[0].Trim().ToLower();
				string val = tokens[1].Trim();

				switch (var)
				{
					case "server":
					case "data source":
						service = val;
						break;

					case "integrated security":
						switch (val.ToLower())
						{
							case "true":
							case "false":
								isIntegratedSecurity = bool.Parse(val);
								break;
							case "sspi":
								isIntegratedSecurity = true;
								break;
							default:
								throw new ArgumentException("unknown value: " + val);
						}
						break;

					case "initial catalog":
						database = val;
						break;

					case "uid":
					case "user id":
						userid = val;
						break;

					case "pwd":
					case "password":
						password = val;
						break;

					default:
						otherPairs.Add(var, val);
						break;
					//throw new ArgumentException("unknown token: " + var);
				}
			}
		}
		#endregion

		#region Private Methods
		#endregion

		#region Protected Methods
		#endregion

		#region Properties
		/// <summary>
		/// Get or set the ConnectionString
		/// </summary>
		public string ConnectionString
		{
			get
			{
				return MakeConnectionString();
			}
			set
			{
				Parse(value);
			}
		}

		/// <summary>
		/// Get a value whether all elements are specified.
		/// </summary>
		public bool IsInitialized
		{
			get
			{
				// DariusBacon algorithm: condition && !switch
				return string.IsNullOrEmpty(service) &&
					string.IsNullOrEmpty(database) &&
					(
					(string.IsNullOrEmpty(userid) && string.IsNullOrEmpty(password)) &&
					!isIntegratedSecurity
					);
			}
		}

		/// <summary>
		/// Get or set the Service element.
		/// </summary>
		public string Service
		{
			get
			{
				return service;
			}
			set
			{
				service = value;
			}
		}

		/// <summary>
		/// Get or set the Database element.
		/// </summary>
		public string Database
		{
			get
			{
				return database;
			}
			set
			{
				database = value;
			}
		}

		/// <summary>
		/// Get or set the UserID element.
		/// </summary>
		public string Userid
		{
			get
			{
				return userid;
			}
			set
			{
				userid = value;
			}
		}

		/// <summary>
		/// Get or set the Password element.
		/// </summary>
		public string Password
		{
			get
			{
				return password;
			}
			set
			{
				password = value;
			}
		}

		/// <summary>
		/// Get or set the IntegratedSecurity element.
		/// </summary>
		public bool IsIntegratedSecurity
		{
			get
			{
				return isIntegratedSecurity;
			}
			set
			{
				isIntegratedSecurity = value;
			}
		}

		/// <summary>
		/// return any pair(s) that the manager does not understand.
		/// </summary>
		public string OtherPairs
		{
			get
			{
				StringBuilder s = new StringBuilder();

				foreach (KeyValuePair<string, string> kv in otherPairs)
				{
					if (s.Length > 0)
						s.Append(";");
					s.Append(kv.Key + "=" + kv.Value);
				}

				return s.ToString();
			}
		}
		#endregion

		#region Others
		#endregion
	}
}
